package com.flute.framework.util.ftp;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

import com.flute.framework.FluteMonitor;
import com.flute.framework.monitor.EventLogger;

/**
 * @author mawg
 * 
 */
public class FtpServer {
	private FTPClient ftpClient;

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#connectServer(ftp.FtpConfig)
	 */
	public void connectServer(FtpConfig ftpConfig) throws SocketException,
			IOException {

		String server = ftpConfig.getServer();
		int port = ftpConfig.getPort();
		String user = ftpConfig.getUsername();
		String password = ftpConfig.getPassword();
		String location = ftpConfig.getLocation();
		String charset = ftpConfig.getCharset();
		int filetype = ftpConfig.getFiletype();
		connectServer(server, port, user, password, location, charset, filetype);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#connectServer(java.lang.String, int,
	 * java.lang.String, java.lang.String, java.lang.String)
	 */
	public void connectServer(String server, int port, String user,
			String password, String path, String charset, int filetype)
			throws SocketException, IOException {
		EventLogger.info(" server:" + server + "; user:" + user + "; port:"
				+ port + "; password:" + password + "; path:" + path
				+ "; charset:" + charset + "; filetype:" + filetype,
				FluteMonitor.getIndexerKey());

		ftpClient = new FTPClient();
		// 下载中文名文件是乱码，所以改为了GBK
		ftpClient.setControlEncoding(charset);

		ftpClient.connect(server, port);
		boolean bo = ftpClient.login(user, password);
		ftpClient.enterLocalPassiveMode();
		ftpClient.setFileType(filetype);
		String message = (bo ? "登陆成功：" : "登陆失败：");
		// Path is the sub-path of the FTP path
		if (path.length() != 0) {
			bo = ftpClient.changeWorkingDirectory(path);
			message = bo ? "更换目录成功：" : "更换目录失败：";
			EventLogger.info(message, FluteMonitor.getIndexerKey());
		}
	}

	public boolean back() throws IOException {
		return ftpClient.changeToParentDirectory();
	}

	public boolean back(int n) throws IOException {
		if (n > 0) {
			boolean result = Boolean.TRUE;
			for (int i = 0; i < n; i++) {
				result &= back();
			}
			return result;
		} else {
			return Boolean.FALSE;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#setFileType(int)
	 */
	public void setFileType(int fileType) throws IOException {
		ftpClient.setFileType(fileType);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#closeServer()
	 */
	public void closeServer() throws IOException {
		if (ftpClient.isConnected()) {
			ftpClient.disconnect();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#changeDirectory(java.lang.String)
	 */
	public boolean changeDirectory(String path) throws IOException {
		return ftpClient.changeWorkingDirectory(path);
	}

	public boolean changeDirectory(String[] paths, int length)
			throws IOException {
		if (paths != null && length > 0) {
			boolean successful = Boolean.TRUE;
			for (int i = 0; successful && i < Math.min(length, paths.length); i++) {
				successful = changeDirectory(paths[i]);
			}
			return successful;
		} else {
			return Boolean.FALSE;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#createDirectory(java.lang.String)
	 */
	public boolean createDir(String pathName) throws IOException {
		return ftpClient.makeDirectory(pathName);
	}

	public boolean createNewFile(String pathName) throws IOException {
		if (StringUtils.isEmpty(pathName)) {
			return Boolean.FALSE;
		}
		ByteArrayInputStream bais = new ByteArrayInputStream("".getBytes());
		return ftpClient.storeFile(pathName, bais);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#removeDirectory(java.lang.String)
	 */
	public boolean removeDirectory(String path) throws IOException {
		if (StringUtils.isEmpty(path)) {
			return Boolean.FALSE;
		}
		return removeDirectory(path, Boolean.FALSE);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#removeDirectory(java.lang.String, boolean)
	 */
	public boolean removeDirectory(String path, boolean isAll)
			throws IOException {
		if (isAll) {
			ftpClient.setSoTimeout(0);
			FTPFile[] ftpFileArr = ftpClient.listFiles(path);
			if (ftpFileArr != null && ftpFileArr.length > 0) {
				for (FTPFile ftpFile : ftpFileArr) {
					String name = ftpFile.getName();
					if (ftpFile.isDirectory()) {
						System.out.println("* [sD]Delete subPath [" + path
								+ "/" + name + "]");
						if (!ftpFile.getName().equals(".")
								&& (!ftpFile.getName().equals(".."))) {
							removeDirectory(path + "/" + name, Boolean.TRUE);
						}
					} else if (ftpFile.isFile()) {
						System.out.println("* [sF]Delete file [" + path + "/"
								+ name + "]");
						if (!deleteFile(path + "/" + name)) {
							EventLogger.error("删除文件夹'" + ftpFile.getName()
									+ "'失败", FluteMonitor.getIndexerKey());
						}
					} else if (ftpFile.isSymbolicLink()) {

					} else if (ftpFile.isUnknown()) {

					}
				}
			}
		}
		return ftpClient.removeDirectory(path);
	}

	public long size(String path) throws IOException {
		FTPFile[] ftpFileArr = ftpClient.listFiles();
		if (ftpFileArr != null) {
			for (FTPFile ftpFile : ftpFileArr) {
				if (ftpFile.isFile() && ftpFile.getName().equals(path)) {
					return ftpFile.getSize();
				}
			}
		}
		return -1;
	}

	public long lastModified(String path) throws IOException {
		FTPFile[] ftpFileArr = ftpClient.listFiles();
		if (ftpFileArr != null) {
			for (FTPFile ftpFile : ftpFileArr) {
				if (ftpFile.getName().equals(path)) {
					Calendar c = ftpFile.getTimestamp();
					return c.getTimeInMillis();
				}
			}
		}
		return -1;
	}

	public boolean exists(String path) throws IOException {
		FTPFile[] ftpFileArr = ftpClient.listFiles();
		if (ftpFileArr != null) {
			for (FTPFile ftpFile : ftpFileArr) {
				if (ftpFile.getName().equals(path)) {
					return Boolean.TRUE;
				}
			}
		}
		return Boolean.FALSE;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#existDirectory(java.lang.String)
	 */
	public boolean isFile(String path) throws IOException {
		FTPFile[] ftpFileArr = ftpClient.listFiles();
		if (ftpFileArr != null) {
			for (FTPFile ftpFile : ftpFileArr) {
				if (ftpFile.isFile() && ftpFile.getName().equals(path)) {
					return Boolean.TRUE;
				}
			}
		}
		return Boolean.FALSE;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#existDirectory(java.lang.String)
	 */
	public boolean isDir(String path) throws IOException {
		FTPFile[] ftpFileArr = ftpClient.listFiles();
		if (ftpFileArr != null) {
			for (FTPFile ftpFile : ftpFileArr) {
				if (ftpFile.isDirectory() && ftpFile.getName().equals(path)) {
					return Boolean.TRUE;
				}
			}
		}
		return Boolean.FALSE;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#getFileList(java.lang.String)
	 */
	public List<String> getFileList(String path) throws IOException {
		FTPFile[] ftpFiles = ftpClient.listFiles(path);
		List<String> retList = new ArrayList<String>();
		if (ftpFiles == null || ftpFiles.length == 0) {
			return retList;
		}
		for (FTPFile ftpFile : ftpFiles) {
			retList.add(ftpFile.getName());
		}
		return retList;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#getFileList(java.lang.String, java.lang.String)
	 */
	public long getFileList(String fileName, String path) throws IOException {
		FTPFile[] ftpFiles = ftpClient.listFiles(path);
		if (ftpFiles == null || ftpFiles.length == 0) {
			return 0;
		}
		fileName = (fileName == null ? StringUtils.EMPTY : fileName);
		for (FTPFile ftpFile : ftpFiles) {
			if (ftpFile.isFile()) {
				System.out.println(fileName + "=\n" + ftpFile.getName());
				if (fileName.equals(ftpFile.getName().trim())) {
					return ftpFile.getSize();
				}
			}
		}
		return 0;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#deleteFile(java.lang.String)
	 */
	public boolean deleteFile(String pathName) throws IOException {
		if (StringUtils.isEmpty(pathName)) {
			return Boolean.FALSE;
		}
		return ftpClient.deleteFile(pathName);
	}

	// #2. upload to ftp server
	// InputStream <------> byte[] simple and See API

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#uploadFile(java.lang.String, java.lang.String)
	 */
	public boolean uploadFile(String fileName, String newName)
			throws IOException {
		boolean flag = Boolean.FALSE;
		InputStream iStream = null;
		try {
			iStream = new FileInputStream(fileName);
			flag = ftpClient.storeFile(newName, iStream);
		} catch (IOException e) {
			flag = Boolean.FALSE;
			e.printStackTrace();
			return flag;
		} finally {
			IOUtils.closeQuietly(iStream);
		}
		return flag;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#uploadFile(java.lang.String)
	 */
	public boolean uploadFile(String fileName) throws IOException {
		return uploadFile(fileName, fileName);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#uploadFile(java.io.InputStream,
	 * java.lang.String)
	 */
	public boolean uploadFile(InputStream iStream, String newName)
			throws IOException {
		boolean flag = Boolean.FALSE;
		try {
			// can execute [OutputStream storeFileStream(String remote)]
			// Above method return's value is the local file stream.
			flag = ftpClient.storeFile(newName, iStream);
		} catch (IOException e) {
			flag = Boolean.FALSE;
			return flag;
		} finally {
			IOUtils.closeQuietly(iStream);
		}
		return flag;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#download(java.lang.String, java.lang.String)
	 */
	public boolean download(String remoteFileName, String localFileName)
			throws IOException {

		boolean flag = Boolean.FALSE;
		File outfile = new File(localFileName);
		OutputStream oStream = null;
		try {
			if (!outfile.exists()) {
				FileUtils.forceMkdir(outfile.getParentFile());
			}
			oStream = FileUtils.openOutputStream(outfile);
			flag = ftpClient.retrieveFile(remoteFileName, oStream);
			if (flag) {
				long ftpsize = size(remoteFileName);
				long localsize = new File(localFileName).length();
				flag = ftpsize == localsize;
			}
		} catch (IOException e) {
			flag = Boolean.FALSE;
			e.printStackTrace();
			return flag;
		} finally {
			IOUtils.closeQuietly(oStream);
		}
		return flag;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ftp.IFileOperation1#downFile(java.lang.String)
	 */
	public InputStream downFile(String sourceFileName) throws IOException {
		return ftpClient.retrieveFileStream(sourceFileName);
	}
}